package tronix.util;

import java.io.*;

/**
 * Provides utilities for Base64 encode/decode of binary data.
 */
public class Utils {

    public static boolean debugFlag = true;
    private static byte[] mBase64EncMap, mBase64DecMap;

    /**
     * Class initializer. Initializes the Base64 alphabet (specified in RFC-2045).
     */
    static {
        byte[] base64Map = {
            (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F',
            (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
            (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R',
            (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X',
            (byte) 'Y', (byte) 'Z',
            (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
            (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l',
            (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r',
            (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
            (byte) 'y', (byte) 'z',
            (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
            (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'};
        mBase64EncMap = base64Map;
        mBase64DecMap = new byte[128];
        for (int i = 0; i < mBase64EncMap.length; i++) {
            mBase64DecMap[mBase64EncMap[i]] = (byte) i;
        }
    }

    /**
     * This class isn't meant to be instantinated.
     */
    private Utils() {
    }

    /**
     * Encodes the given byte[] using the Base64-encoding, as specified in RFC-2045 (Section 6.8).
     * <p/>
     * @param aData the data to be encoded
     * <p/>
     * @return the Base64-encoded <var>aData</var>
     * <p/>
     * @exception IllegalArgumentException if NULL or empty array is passed
     */
    public static String base64Encode(byte[] aData) {
        if ((aData == null) || (aData.length == 0)) {
            throw new IllegalArgumentException("Can not encode NULL or empty byte array.");
        }

        byte encodedBuf[] = new byte[((aData.length + 2) / 3) * 4];

        // 3-byte to 4-byte conversion 
        int srcIndex, destIndex;
        for (srcIndex = 0, destIndex = 0; srcIndex < aData.length - 2; srcIndex += 3) {
            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex] >>> 2) & 077];
            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex + 1] >>> 4) & 017
                    | (aData[srcIndex] << 4) & 077];
            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex + 2] >>> 6) & 003
                    | (aData[srcIndex + 1] << 2) & 077];
            encodedBuf[destIndex++] = mBase64EncMap[aData[srcIndex + 2] & 077];
        }

        // Convert the last 1 or 2 bytes 
        if (srcIndex < aData.length) {
            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex] >>> 2) & 077];
            if (srcIndex < aData.length - 1) {
                encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex + 1] >>> 4) & 017
                        | (aData[srcIndex] << 4) & 077];
                encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex + 1] << 2) & 077];
            } else {
                encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex] << 4) & 077];
            }
        }

        // Add padding to the end of encoded data 
        while (destIndex < encodedBuf.length) {
            encodedBuf[destIndex] = (byte) '=';
            destIndex++;
        }

        String result = new String(encodedBuf);
        return result;
    }

    /**
     * Decodes the given Base64-encoded data, as specified in RFC-2045 (Section 6.8).
     * <p/>
     * @param aData the Base64-encoded aData.
     * <p/>
     * @return the decoded <var>aData</var>.
     * <p/>
     * @exception IllegalArgumentException if NULL or empty data is passed
     */
    public static byte[] base64Decode(String aData) {
        if ((aData == null) || (aData.length() == 0)) {
            throw new IllegalArgumentException("Can not decode NULL or empty string.");
        }

        byte[] data = aData.getBytes();

        // Skip padding from the end of encoded data 
        int tail = data.length;
        while (data[tail - 1] == '=') {
            tail--;
        }

        byte decodedBuf[] = new byte[tail - data.length / 4];

        // ASCII-printable to 0-63 conversion 
        for (int i = 0; i < data.length; i++) {
            data[i] = mBase64DecMap[data[i]];
        }

        // 4-byte to 3-byte conversion 
        int srcIndex, destIndex;
        for (srcIndex = 0, destIndex = 0; destIndex < decodedBuf.length - 2;
                srcIndex += 4, destIndex += 3) {
            decodedBuf[destIndex] = (byte) (((data[srcIndex] << 2) & 255)
                    | ((data[srcIndex + 1] >>> 4) & 003));
            decodedBuf[destIndex + 1] = (byte) (((data[srcIndex + 1] << 4) & 255)
                    | ((data[srcIndex + 2] >>> 2) & 017));
            decodedBuf[destIndex + 2] = (byte) (((data[srcIndex + 2] << 6) & 255)
                    | (data[srcIndex + 3] & 077));
        }

        // Handle last 1 or 2 bytes 
        if (destIndex < decodedBuf.length) {
            decodedBuf[destIndex] = (byte) (((data[srcIndex] << 2) & 255)
                    | ((data[srcIndex + 1] >>> 4) & 003));
        }
        if (++destIndex < decodedBuf.length) {
            decodedBuf[destIndex] = (byte) (((data[srcIndex + 1] << 4) & 255)
                    | ((data[srcIndex + 2] >>> 2) & 017));
        }

        return decodedBuf;
    }

    /**
     * Wstrzymuje pracę na n sekund 
     */
    public static void wait(float n) {

//        System.out.println("waiting " + n + " seconds");
        long t0, t1;

        t0 = System.currentTimeMillis();

        do {
            t1 = System.currentTimeMillis();
        } while ((t1 - t0) < (n * 1000));
    }

    /**
     * Usuwanie plznakow, cos a`la iconv //translit
     * <p/>
     * @param input < p/>
     * <p/>
     * @return
     */
    public static String asciiNormalize(String input) {

        String filtered = input;
        filtered = filtered.replace("ą", "a");
        filtered = filtered.replace("ć", "c");
        filtered = filtered.replace("ę", "e");
        filtered = filtered.replace("ł", "l");
        filtered = filtered.replace("ń", "n");
        filtered = filtered.replace("ó", "o");
        filtered = filtered.replace("ś", "s");
        filtered = filtered.replace("ź", "z");
        filtered = filtered.replace("ż", "z");

        filtered = filtered.replace("Ą", "A");
        filtered = filtered.replace("Ć", "C");
        filtered = filtered.replace("Ę", "E");
        filtered = filtered.replace("Ł", "L");
        filtered = filtered.replace("Ń", "N");
        filtered = filtered.replace("Ó", "O");
        filtered = filtered.replace("Ś", "S");
        filtered = filtered.replace("Ź", "Z");
        filtered = filtered.replace("Ż", "Z");


        filtered = filtered.replaceAll("[^a-zA-Z0-9-]", " ");
        filtered = filtered.replaceAll(" {2,}", " ");

        return filtered;

    }

    public static void saveToFile(String fileName, String resultStr) {

        try {
            FileWriter fileWriter;
            File newTextFile = new File(fileName);
            fileWriter = new FileWriter(newTextFile,true);
            fileWriter.write(resultStr);
            fileWriter.close();
        } catch (IOException iOException) {
        }


    }

    public static void saveToFile(String fileName, byte[] data) {
        try {
            try (FileOutputStream out = new FileOutputStream(fileName, true)) {
                out.write(data);
            }
        } catch (IOException iOException) {
            System.err.println(iOException.getMessage());
        }
    }

    public static void printConsole(Object err) {
        System.out.println(err);
    }

    public static void printError(Object err) {
        System.err.println(err);
    }

    /**
     * returns byte[] as hexstring
     * @param data
     * @return 
     */
    public static String byteArrayToHexString(byte[] data) {
        StringBuilder sb = new StringBuilder();
        StringBuilder sb1 = new StringBuilder();
        for (byte b : data) {
            sb.append(String.format("%02X ", b));
            if(b>0x20 && b<0x7F){
                sb1.append(String.format(" %c ", b));
            }else{
                sb1.append(String.format("%02X ", b));
            }
        }
        return sb.toString()+"\n"+sb1.toString();
    }
    
    
}
